﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.IO;
using Grundy.Common;
using Grundy.CryptographicServices;
using Grundy.Entity;
using Grundy.Key.RsaProvider;
using Grundy.Licensing.Server.Command;
using Grundy.Message;
using log4net;
using System.Linq;

namespace Grundy.Licensing.Server
{
    public class Application : IApplication
    {
        ILog _logger = log4net.LogManager.GetLogger(typeof(Application));

        private static Application _instance = new Application();
        
        protected Application()
        {
            // Set license database strategy
            Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<LicenseDatabase>());

            NodeIdentifiers = GetNodeFingerprint();
            EntitlementServerCryptographicServicesProvider = CreateCryptographicServicesProviders(EntitlementServer_RsaProvider_Public.Key);
            ServerCryptographicServicesProvider = CreateCryptographicServicesProviders(Server_RsaProvider_Private.Key);

            ServerConfiguration = GetServerConfiguration();
            ExecutionCounter =  LoadExecutionCounter();
            LicensingStrategyFactory = new LicensingStrategyFactory(ExecutionCounter);
            LicenseStore =  CreateLicenseStore();
            LicenseSessionStore = CreateLicenseSessionStore();

            CustomerCryptographicServicesProviderFactory = new Sha256MacProviderFactory(LicenseStore);
            StartServer();
        }

        public virtual LicensingStrategyFactory LicensingStrategyFactory { get; set; }

        private LicenseSessionStore CreateLicenseSessionStore()
        {
            return new LicenseSessionStore(LicenseStore, LicensingStrategyFactory, new TimeSpan(0, 0, 0, ServerConfiguration.CleanupEveryNSeconds));
        }

        private ExecutionCounter LoadExecutionCounter()
        {
            List<ExecutionCount> executionCounts = null;
            using(var db = new LicenseDatabase())
            {
                executionCounts = db.ExecutionCounts.ToList();
            }
            return new ExecutionCounter(executionCounts, new TimeSpan(0, 0, 0, 300));
        }

        private IdentifierCollection GetNodeFingerprint()
        {
            var identityProvider = new NodeFingerprintIdentityProvider();
            identityProvider.IgnoreMacAddresses = true;

            return identityProvider.GetIdentifiers();
        }

        private void StartServer()
        {
            LicenseServer = new LicenseServer(ServerConfiguration, LicenseSessionStore, GetLicenseServiceFactory(), GetLicensingStrategyFactory());
            LicenseServer.Start();
        }

        private LicensingStrategyFactory GetLicensingStrategyFactory()
        {
            return new LicensingStrategyFactory(ExecutionCounter);
        }

        public CustomerCryptographicServicesProvider GetCustomerCryptographicServicesProvider(string providerString)
        {
            return CustomerCryptographicServicesProviderFactory.Get(providerString);
        }

        public CustomerCryptographicServicesProviderFactory CustomerCryptographicServicesProviderFactory { get; set; }
        public CryptographicServicesProvider ServerCryptographicServicesProvider { get; private set; }
        public CryptographicServicesProvider EntitlementServerCryptographicServicesProvider { get; private set; }
        public IdentifierCollection NodeIdentifiers { get; private set; }
        public ExecutionCounter ExecutionCounter { get; private set; }
        public LicenseSessionStore LicenseSessionStore { get; private set; }

        private CryptographicServicesProvider CreateCryptographicServicesProviders(string key)
        {
            return new RsaProvider(key);
        }

        private LicenseStore CreateLicenseStore()
        {
            var nodeIdentityComparer = new NodeIdentityComparer(NodeIdentifiers);
            
            var licenseStore = new LicenseStore(new LicenseManager(EntitlementServerCryptographicServicesProvider), nodeIdentityComparer, ServerCryptographicServicesProvider);
            
            var path = ".";
            if (!ServerConfiguration.LicenseDirectoryPath.IsNullOrEmpty())
            {
                path = ServerConfiguration.LicenseDirectoryPath;
            }

            var licenseFiles = Directory.EnumerateFiles(path, "*.{0}".FormatWith(ServerConfiguration.LicenseFileExtension));
            foreach (var licenseFile in licenseFiles)
            {
                try
                {
                    var license = File.ReadAllText(licenseFile);
                    licenseStore.Add(license);
                }
                catch (Exception)
                {
                   _logger.ErrorFormat("License file {0} is not valid.", licenseFile);
                }
            }

            return licenseStore;
        }

        private ServerConfiguration GetServerConfiguration()
        {
            return new ServerConfiguration {Port = 2225, MaximumMessageSize = 32768, LicenseFileExtension = "glf", CleanupEveryNSeconds = 600};
        }

        public LicenseServer LicenseServer { get; private set; }

        public static Application Instance { get { return _instance; } }

        public IEnumerable<LicenseData> GetLicensesData()
        {
            return LicenseServer.GetLicensesData();
        }

        public LicenseServiceFactory GetLicenseServiceFactory()
        {
            return new LicenseServiceFactory(this);
        }

        public LicenseStore LicenseStore { get; private set; }

        public ServerConfiguration ServerConfiguration { get; private set; }
    }
}